package com.idealighter.game.games.errentexaspoker.struct;

import com.google.common.collect.Lists;

import com.idealighter.game.core.common.Game;
import com.idealighter.game.games.common.AbstractRoom;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.SeatState;
import com.idealighter.game.games.errentexaspoker.manager.ErrenTexapokerDataMgr;
import com.idealighter.game.games.errentexaspoker.manager.ErrenTexapokerMgr;
import com.idealighter.game.games.texaspoker.struct.Deck;
import com.idealighter.game.games.texaspoker.struct.cards.Card;
import com.idealighter.game.games.texaspoker.util.HandPower;
import com.idealighter.game.schedule.manager.ScheduleMgr;
import com.idealighter.game.server.context.ApplicationContext;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;

/**
 * 二人德州扑克房间牌桌 .
 */
public class ErrenTexapokerRoom extends AbstractRoom {

  // 房间中的桌子
  public final Map<Integer, Table> tables;

  public ErrenTexapokerRoom(int id, String name, int tableNum) {
    super(id, name);
    this.tables = createTables(tableNum);
  }

  /**
   * 创建桌子.
   * 
   * @param tableNum . 桌子数量
   * @return
   */
  private Map<Integer, Table> createTables(int tableNum) {
    Map<Integer, Table> tables = new LinkedHashMap<>(tableNum);
    for (int i = 0; i < tableNum; i++) {
      int tableId = id.intValue() * Table.MAX_TABLE + i + 1;

      Table table = new Table(tableId);
      tables.put(table.getId().intValue(), table);
    }

    return tables;
  }

  /**
   * 德州扑克桌子 .
   */
  public class Table extends AbstractTable {
    // 最大桌子数
    public static final int MAX_TABLE = 100000;

    // 座位数量
    public static final int SEAT_NUM = 2;

    // //牌
    // Deck deck = new Deck();

    // 所属房间
    public final ErrenTexapokerRoom room = ErrenTexapokerRoom.this;
    // 牌桌的座位
    public final List<Seat> seats;
    // 一副牌
    public final List<Card> cards = new Deck().getCards();

    // 公共牌
    public List<Card> commonCards = Lists.newArrayList();

    // 当前最大注
    public long maxBet = 0;

    // 加注数
    public long raiseBet = 0;

    // 计时器
    public ScheduleMgr scheduleMgr = null;
    // 阶段(0发牌，1第一轮下注,2发公共牌3张,3第二轮下注,4第二次发牌,5第三轮下注，6第三次发牌，7第四轮下注, 8,结束，结算)
    public int state = 0;
    // 牌序
    public int cardIndex = 0;

    // 庄家位置
    public byte landlordOrder = 0;
    // 大盲注位置
    public byte bigBind = 0;
    // 小盲注位置
    public byte smallBind = 0;
    // 下一个应该叫牌玩家位置,0代表第一个为位置

    // 当前下注的玩家的位置
    public int curOrder = -1;
    public int nextCallOrder = -1;
    // 下一个应该出牌的玩家位置
    public int nextPlayOrder = -1;
    // 上一次出牌的玩家位置
    public int prePlayOrder = -1;
    // 上一次玩家出的牌
    public List<Card> preCards = null;
    // 上一次玩家出的牌的类型
    // public CardsType preCardsType = null;
    // 游戏的倍数
    public int multiple = 1;

    // 总下注筹码数
    public int totalChips = 0;

    // 发牌是否结束
    public boolean isdealCardOver = false;

    // 玩家退出时遗留下来的筹码
    public long exitChips = 0;

    // 准备人数->防止一人准备就发牌
    public int readyCount = 0;

    // 是否在游戏中
    public boolean isGaming = false;

    // 上一个人下注时，玩家筹码是否相等
    public boolean preBet = true;

    // 是否立刻结算
    public boolean isBanlance = false;

    /**
     * 构造函数.
     * 
     * @param id .
     */
    private Table(int id) {
      super(id);
      this.seats = createSeats();
    }

    @SuppressWarnings("unchecked")
    @Override
    public ErrenTexapokerRoom room() {
      return room;
    }

    /**
     * 下一个位置order.
     * 
     * @param seat 座位信息.
     * @return
     */
    public int nextSeatOrder(Seat seat) {
      // int order = seat.order;
      // if (order + 1 > seats.size()) {
      // order = 1;
      // } else {
      // order += 1;
      // }
      // int index = order;
      // for (int i = index; i < seats.size(); i++) {
      // if (seats.get(index - 1).playerId == 0 || seats.get(index -
      // 1).isAllIn || seats.get(index - 1).isFold) {
      // index++;
      // } else {
      // return index;
      // }
      // }
      // return index;
      int order = seat.getOrder();
      Seat nextSeat;
      for (int i = 0; i < seats.size(); i++) {
        order += 1;
        if (order > seats.size()) {
          order -= seats.size();
        }
        nextSeat = seats.get(order - 1);
        if (nextSeat.getPlayerId() > 0 && nextSeat.isFold == false && nextSeat.isAllIn == false) {
          return nextSeat.getOrder();
        }
      }
      return 1;
    }

    /**
     * 下一个位置order.
     * 
     * @param order .
     * @return
     */
    public int nextSeatOrder(int order) {
      Seat nextSeat;
      for (int i = 0; i < seats.size(); i++) {
        order += 1;
        if (order > seats.size()) {
          order -= seats.size();
        }
        nextSeat = seats.get(order - 1);
        if (nextSeat.getPlayerId() > 0 && nextSeat.isFold == false && nextSeat.isAllIn == false) {
          return nextSeat.getOrder();
        }
      }
      return 1;
    }

    /**
     * 下一个位置.
     * 
     * @param seat 座位信息.
     * @return
     */
    public Seat nextSeat(Seat seat) {
      return seats.get(nextSeatOrder(seat));
    }

    /**
     * 上一个位置.
     * 
     * @param seat 座位信息.
     * @return
     */
    public Seat preSeat(Seat seat) {
      return seats.get(nextSeatOrder(seat));
    }

    /**
     * 上一个位置坐标.
     *
     * @param seat 座位信息.
     * @return
     */

    public int preSeatOrder(Seat seat) {
      int index = seat.getOrder() - 1;
      if (index <= 0) {
        index += seats.size();
      }
      for (int i = index; i <= seats.size(); i++) {
        if (seats.get(index - 1).getPlayerId() == 0 || seats.get(index - 1).isAllIn
            || seats.get(index - 1).isFold) {
          index--;
        } else {
          return index;
        }
      }

      return index;
    }

    /**
     * 获取牌桌的庄家的位置.
     * 
     * @return
     */
    public Seat landlord() {
      for (Seat seat : seats) {
        if (seat.landlord) {
          return seat;
        }
      }

      return null;
    }

    /**
     * 创建座位.
     * 
     * @return
     */
    private List<Seat> createSeats() {
      List<Seat> seats = new ArrayList<>();
      for (byte i = 1; i <= SEAT_NUM; i++) {
        seats.add(new Seat(i));
      }

      return Collections.unmodifiableList(seats);
    }

    /**
     * 重置牌桌 .
     */
    public void reset() {
      this.nextCallOrder = -1;
      this.nextPlayOrder = -1;
      this.prePlayOrder = -1;
      this.preCards = null;
      // this.preCardsType = null;
      this.multiple = 1;
      this.raiseBet = 0;
      this.curOrder = -1;
      // this.isdealCardOver = false;
      this.exitChips = 0;
      this.readyCount = 0;
      this.isGaming = false;
      this.cardIndex = 0;
      this.totalChips = 0;
      this.preBet = true;
      this.maxBet = 0;
      this.commonCards.clear();
      this.isBanlance = false;
    }

    /**
     * @return 获取TableInfo
     */
    /*
     * public . TableInfo tableInfo() { TableInfo tableInfo = new TableInfo(); tableInfo.setId(id);
     * tableInfo.setRoomId(room.id); seats.forEach((seat) ->
     * tableInfo.getSeats().add(seat.seatInfo()));
     * 
     * return . tableInfo; }
     */

    /**
     * 牌桌的底牌公共牌.
     * 
     * @return
     */
    public List<Card> hiddenCards() {

      return cards.subList(cards.size() - ErrenTexapokerMgr.BOARD_CARD, cards.size());
    }

    /**
     * 德州扑克座位 .
     */
    public class Seat extends AbstractSeat {
      // 所属桌子
      public final Table table = Table.this;
      // 牌数据->手牌
      public final List<Card> cards = Lists.newArrayList();
      // 是否准备好
      public boolean ready = false;
      // 是否托管
      public boolean hosted = false;
      // 是否是庄家
      public boolean landlord = false;
      // 出牌次数
      public int playNum = 0;
      // 玩家是否加倍
      public boolean doubled = false;
      // 玩家总下注筹码
      public long bet = 0;
      // 玩家总下注筹码->临时存储
      public long tempbet = 0;
      // 玩家当前轮次的下注数
      public int curBet = 0;

      public List<Integer> betList = Lists.newArrayList();
      // 玩家结算筹码
      public long billBet = 0;
      // 玩家总筹码
      // public int totalChips = 0;
      // 是否梭哈
      public boolean isAllIn = false;
      // 是否弃牌
      public boolean isFold = false;
      // 是否有一次操作
      public boolean isBet = false;
      // 结算牌大小
      public HandPower handPower = null;

      // 结算的大小
      public int power = 0;
      // 临时存储
      public long tempTotal = 0;

      public boolean isFlag = false;
      // 牌是否最大(用于机器人控制)
      public int isWin = 0;
      // 是否系统托管(已放弃)
      public boolean systemHosted = false;
      public ScheduledFuture<?> stepFuture = null;

      public Seat(byte order) {
        super(order);
      }

      public int getPower() {
        return power;
      }

      @Override
      public boolean equals(Object obj) {
        if (!(obj instanceof Card)) {
          return false;
        }
        Seat other = (Seat) obj;
        return order == other.order;
      }

      @SuppressWarnings("unchecked")
      @Override
      public Table table() {
        return table;
      }

      /**
       * @return 获取SeatInfo
       */
      /*
       * public . SeatInfo seatInfo() { SeatInfo seatInfo = new SeatInfo();
       * seatInfo.setOrder(order); seatInfo.setPlayerId(playerId);
       * seatInfo.setPlayerName(playerName); seatInfo.setTableId(table.id); seatInfo.setReady(ready
       * ? (byte) 1 : (byte) 0); seatInfo.setChips(totalChips);
       * seatInfo.setSystemHosted(systemHosted ? 1 : 0); return seatInfo; }
       */

      /**
       * 重置座位数据 .
       */
      public void reset() {
        this.ready = false;
        this.landlord = false;
        this.hosted = false;
        this.playNum = 0;
        this.doubled = false;
        this.cards.clear();
        this.isFold = false;
        this.isAllIn = false;
        this.isBet = false;
        this.power = 0;
        this.handPower = null;
        this.billBet = 0;
        this.tempbet = 0;
        this.bet = 0;
        this.curBet = 0;
        this.state = SeatState.SEATED;
        this.betList.clear();
        this.tempTotal = 0;
        this.isWin = 0;
        this.isFlag = false;
        this.totalChips = 0;
      }

      /**
       * 重置座位数据除了准备 .
       */
      public void resetButReady() {
        this.landlord = false;
        this.hosted = false;
        this.playNum = 0;
        this.doubled = false;
        this.cards.clear();
      }

      /**
       * 重置座位数据除了totalChips .
       */
      public void resetButTotalChips() {
        long totalChips = this.totalChips;
        reset();
        this.totalChips = totalChips;
      }

      /**
       * 清空座位数据 .
       */
      public void clear() {
        this.playerId = 0;
        this.playerName = null;
        reset();
      }

    }

    @Override
    public List<Seat> seats() {
      return seats;
    }
  }

  @Override
  public Game game() {
    return Game.ERREN_TEXAPOKER;
  }

  @Override
  public AbstractSeat seat(long playerId) {
    return ApplicationContext.getBean(ErrenTexapokerDataMgr.class).getPlayerSeat(playerId);
  }

  @Override
  public Collection<? extends AbstractTable> tables() {
    return tables.values();
  }

}
